GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#2843)
by Brendan
04:11
created

symphony.suggestions.js ➔ handleChange   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
c 0
b 0
f 0
nc 5
nop 1
dl 0
loc 32
rs 4.909
1
/**
2
 * @package assets
3
 */
4
5
(function($, Symphony) {
6
	'use strict';
7
8
	Symphony.Interface.Suggestions = function() {
9
10
		var context;
11
12
		/**
13
		 * Initialise suggestions
14
		 */
15
		var init = function(element, selector) {
16
			context = $(element);
17
18
			// Disable autocomplete
19
			context.find(selector).each(function() {
20
				this.autocomplete = 'off';
21
			});
22
23
			// Create suggestion lists
24
			createSuggestions(selector);
25
26
			// Interactions
27
			context.on('input.suggestions', selector, handleChange);
28
			context.on('click.suggestions', selector, handleChange);
29
			context.on('focus.suggestions', selector, handleChange);
30
			context.on('keyup.suggestions', selector, handleChange);
31
			context.on('mouseover.suggestions', '.suggestions li:not(.help):not(.calendar)', handleOver);
32
			context.on('mouseout.suggestions', '.suggestions li:not(.help):not(.calendar)', handleOut);
33
			context.on('mousedown.suggestions', '.suggestions li:not(.help):not(.calendar)', handleSelect);
34
			context.on('keydown.suggestions', selector, handleNavigation);
35
		};
36
37
	/*-------------------------------------------------------------------------
38
		Event handling
39
	-------------------------------------------------------------------------*/
40
41
		/**
42
		 * Load suggestions based on type while the user types.
43
		 */
44
		var handleChange = function(event) {
45
			var input = $(this),
46
				value = input.val(),
47
				suggestions = input.next('.suggestions'),
48
				types = suggestions.attr('data-search-types'),
49
				trigger = input.attr('data-trigger');
50
51
			// Stop when navigating the suggestion list
52
			if(jQuery.inArray(event.which, [13, 27, 38, 40]) !== -1) {
53
				return;
54
			}
55
56
			// Dates
57
			if(types && types.indexOf('date') !== -1) {
58
				schedule(input);
59
			}
60
61
			// Tokens
62
			else if(value && trigger) {
63
				tokenize(input, suggestions, value, trigger);
64
			}
65
66
			// Entries
67
			else if(value || (types && types.indexOf('static') !== -1)) {
68
				load(input, value);
69
			}
70
71
			// No input
72
			else {
73
				clear(suggestions);
74
			}
75
		};
76
77
		/**
78
		 * Handle mouse interactions on the suggestion list.
79
	     * In order to make this work with the keyboard as well, set the class
80
	     * `.active` to the current target.
81
	     *
82
	     * @param Event event
83
	     *  The mouseover event
84
		 */
85
		var handleOver = function(event) {
86
			var suggestion = $(event.target);
87
88
			suggestion.siblings('li:not(.help)').removeClass('active');
89
			suggestion.addClass('active');
90
		};
91
92
		/**
93
		 * Handle finished mouse interactions on the suggestion list and
94
	     * remove `.active` class set by `handleOver`.
95
	     *
96
	     * @param Event event
97
	     *  The mouseout event
98
		 */
99
		var handleOut = function(event) {
100
			var suggestion = $(event.target);
101
102
			suggestion.removeClass('active');
103
		};
104
105
		/**
106
		 * Handle keyboard navigation in the suggestion list.
107
	     *
108
	     * @param Event event
109
	     *  The keydown event
110
		 */
111
		var handleNavigation = function(event) {
112
			var input = $(this),
113
				active;
114
115
			// Down
116
			if(event.which == 40) {
117
				event.preventDefault();
118
				down(input);
119
			}
120
121
			// Up
122
			else if(event.which == 38) {
123
				event.preventDefault();
124
				up(input);
125
			}
126
127
			// Exit
128
			else if(event.which == 27) {
129
				event.preventDefault();
130
				input.blur();
131
			}
132
133
			// Enter
134
			else if(event.which == 13) {
135
				event.preventDefault();
136
				active = input.next('.suggestions').find('li:not(.help).active').text();
137
138
				if(active) {
139
					select(active, input);
140
				}
141
			}
142
		};
143
144
		/**
145
		 * Handle suggestion selection by click.
146
	     *
147
	     * @param Event event
148
	     *  The mousedown event
149
		 */
150
		var handleSelect = function(event) {
151
			var input = $(event.target).parent('.suggestions').prev('input');
152
153
			select(event.target.textContent, input);
154
		};
155
156
	/*-------------------------------------------------------------------------
157
		Suggestions
158
	-------------------------------------------------------------------------*/
159
160
		var tokenize = function(input, suggestions, value, trigger) {
161
			var selectionStart = input[0].selectionStart || 0,
162
				before = value.substring(0, selectionStart).split(' '),
163
				after = value.substr(selectionStart).split(' '),
164
				token = before[before.length - 1],
165
				param = before[before.length - 1] + after[0];
166
167
			// Token found
168
			if(token && token.indexOf(trigger) === 0) {
169
				load(input, param);
170
			}
171
			else {
172
				clear(suggestions);
173
			}
174
		};
175
176
		var load = function(input, value) {
177
			var suggestions = input.next('.suggestions'),
178
				types = suggestions.attr('data-search-types'),
179
				trigger = input.attr('data-trigger'),
180
				query = value,
181
				prefix, data, url;
182
183
			// Prefix
184
			if(trigger) {
185
				prefix = trigger.substr(0, 1);
186
			}
187
188
			// Get value
189
			if(!query) {
190
				query = input.val();
191
			}
192
193
			if(prefix === '{') {
0 ignored issues
show
Bug introduced by
The variable prefix does not seem to be initialized in case trigger on line 184 is false. Are you sure this can never be the case?
Loading history...
194
				query = query.substr(1);
195
			}
196
197
			// Get data
198
			if(types && types.indexOf('parameters') !== -1) {
199
				url = Symphony.Context.get('symphony') + '/ajax/parameters/';
200
				data = {
201
					'query': query
202
				};
203
			}
204
			else {
205
				url = Symphony.Context.get('symphony') + '/ajax/query/';
206
				data = {
207
					'field_id': suggestions.attr('data-field-id'),
208
					'query': query,
209
					'types': types
210
				};
211
			}
212
213
			// Get custom url
214
			if(input.attr('data-url')) {
215
				url = input.attr('data-url');
216
			}
217
218
			// Load suggestions
219
			if(query !== suggestions.attr('data-last-query')) {
220
				suggestions.attr('data-last-query', query);
221
222
				$.ajax({
223
					type: 'GET',
224
					url: url,
225
					data: data,
226
					success: function(result) {
227
						if(types && types.indexOf('parameters') !== -1) {
228
							listtoken(input, suggestions, result);
229
						}
230
						else {
231
							list(suggestions, result);
232
						}
233
					}
234
				});
235
			}
236
		};
237
238
		var listtoken = function(input, suggestions, result) {
239
			var clone = suggestions.clone(),
240
				help = clone.find('.help:first'),
241
				trigger = input.attr('data-trigger'),
242
				prefix;
243
244
			// Prefix
245
			if(trigger) {
246
				prefix = trigger.substr(0, 1);
247
			}
248
249
			// Clear existing suggestions
250
			clear(clone);
251
252
			// Add suggestions
253
			$.each(result, function(index, value) {
254
				if(index === 'status') {
255
					return;
256
				}
257
258
				if(prefix === '{') {
0 ignored issues
show
Bug introduced by
The variable prefix does not seem to be initialized in case trigger on line 245 is false. Are you sure this can never be the case?
Loading history...
259
					value = '{' + value + '}';
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter value. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
260
				}
261
262
				var suggestion = $('<li />', {
263
					text: value
264
				});
265
266
				if(help.length) {
267
					suggestion.insertBefore(help);
268
				}
269
				else {
270
					clone.append(suggestion);
271
				}
272
			});
273
274
			suggestions.replaceWith(clone);
275
		};
276
277
		var list = function(suggestions, result) {
278
			var clone = suggestions.clone(),
279
				help = clone.find('.help:first'),
280
				values = [];
281
282
			// Clear existing suggestions
283
			clear(clone);
284
285
			// Add suggestions
286
			if(result.entries) {
287
				$.each(result.entries, function(index, data) {
288
					values.push(data.value);
289
				});
290
291
				values = values.filter(function(item, index, array) {
292
					return array.indexOf(item) === index;
293
				});
294
295
				$.each(values, function(index, value) {
296
					var suggestion = $('<li />', {
297
						text: value
298
					});
299
300
					if (help.length) {
301
						suggestion.insertBefore(help);
302
					}
303
					else {
304
						clone.append(suggestion);
305
					}
306
				});
307
308
				suggestions.replaceWith(clone);
309
			}
310
		};
311
312
		var schedule = function(input) {
313
			var suggestions = input.next('.suggestions'),
314
				calendar = suggestions.find('.calendar');
315
316
			if(!calendar.length) {
317
				createCalendar(suggestions);
318
			}
319
		};
320
321
		var select = function(value, input) {
322
			var types = input.attr('data-search-types');
323
324
			if(types && types.indexOf('parameters') !== -1) {
325
				insert(value, input);
326
			}
327
			else {
328
				value = value.replace(/,/g, '\\,').replace(/&/g, '%26');
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter value. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
329
				input.val(value);
330
				input.addClass('updated');
331
				input.change();
332
			}
333
334
			clear(input.next('.suggestions'));
335
		};
336
337
		var insert = function(suggestion, input) {
338
			var value = input.val(),
339
				selectionStart = input[0].selectionStart || 0,
340
				beforeSelection = value.substring(0, selectionStart).split(' '),
341
				afterSelection = value.substr(selectionStart).split(' '),
342
				before = '',
343
				after = '';
344
345
			// Get text before parameter
346
			if(beforeSelection.length > 1) {
347
				beforeSelection.pop();
348
				before = beforeSelection.join(' ') + ' ';
349
			}
350
351
			// Get text after parameter
352
			if(afterSelection.length > 1) {
353
				afterSelection.shift();
354
				after = ' ' + afterSelection.join(' ');
355
			}
356
357
			// Insert suggestion
358
			input.val(before + suggestion + after);
359
360
			// Set cursor
361
			var length = before.length + suggestion.length;
362
			input[0].selectionStart = length;
363
			input[0].selectionEnd = length;
364
			input.focus();
365
		};
366
367
		var clear = function(suggestions) {
368
			suggestions.removeAttr('data-last-query');
369
			suggestions.find('li:not(.help)').remove();
370
		};
371
372
		var up = function(input) {
373
			var suggestions = input.next('.suggestions'),
374
				active = suggestions.find('li:not(.help).active').removeClass('active'),
375
				prev = active.prev('li:not(.help):visible');
376
377
			// First
378
			if(active.length === 0 || prev.length === 0) {
379
				suggestions.find('li:not(.help)').last().addClass('active');
380
			}
381
382
			// Next
383
			else {
384
				prev.addClass('active');
385
			}
386
			
387
			stayInFocus(suggestions);
388
		};
389
390
		var down = function(input) {
391
			var suggestions = input.next('.suggestions'),
392
				active = suggestions.find('li:not(.help).active').removeClass('active'),
393
				next = active.next('li:not(.help):visible');
394
395
			// First
396
			if(active.length === 0 || next.length === 0) {
397
				suggestions.find('li:not(.help)').first().addClass('active');
398
			}
399
400
			// Next
401
			else {
402
				next.addClass('active');
403
			}
404
			
405
			stayInFocus(suggestions);
406
		};
407
408
	/*-------------------------------------------------------------------------
409
		Utilities
410
	-------------------------------------------------------------------------*/
411
412
		var createSuggestions = function(selector) {
413
			var inputs = context.find(selector);
414
415
			inputs.each(function() {
416
				var input = $(this),
417
					suggestions = input.next('.suggestions'),
418
					list, types;
419
420
				if(!suggestions.length) {
421
					list = $('<ul class="suggestions" />');
422
423
					types = input.attr('data-search-types');
424
					if(types) {
425
						list.attr('data-search-types', types);
426
					}
427
428
					list.insertAfter(input);
429
				}
430
			});
431
		};
432
433
		var createCalendar = function(suggestions) {
434
			var calendar = new Symphony.Interface.Calendar();
435
436
			suggestions.prepend('<li class="calendar" data-format="YYYY-MM-DD" />');
437
			calendar.init(suggestions.parents('label'));
438
		};
439
440
		var stayInFocus = function(suggestions) {
441
			var active = suggestions.find('li.active'),
442
				distance;
443
444
			// Get distance
445
			if(!active.is(':visible:first')) {
446
				distance = ((active.prevAll().length + 1) * active.outerHeight()) - 180;
447
			}
448
			else {
449
				distance = 0;
450
			}
451
452
			// Focus
453
			suggestions.animate({
454
				'scrollTop': distance
455
			}, 150);
456
		};
457
458
	/*-------------------------------------------------------------------------
459
		API
460
	-------------------------------------------------------------------------*/
461
462
		return {
463
			init: init
464
		};
465
	}();
466
467
	/**
468
	 * Symphony suggestion plugin for jQuery.
469
	 *
470
	 * @deprecated As of Symphony 2.6.0 this plugin is deprecated,
471
	 *  use `Symphony.Interface.Suggestions` instead. This will be
472
	 *  removed in Symphony 3.0
473
	 */
474
	$.fn.symphonySuggestions = function(options) {
475
		var objects = this,
476
			settings = {
477
				trigger: '{$',
478
				source: Symphony.Context.get('path') + '/ajax/parameters/'
479
			};
480
481
		$.extend(settings, options);
482
483
		objects.each(function() {
484
			var input = $(this).find('input[type="text"]');
485
486
			input.attr('data-trigger', settings.trigger);
487
			input.attr('data-url', settings.source);
488
			input.attr('data-search-types', 'parameters');
489
490
			Symphony.Interface.Suggestions.init(this, 'input[type="text"]');
491
		});
492
493
		return objects;
494
	};
495
496
})(window.jQuery, window.Symphony);
497